/**
 * Copyright (c) 2014-2017, huli.com
 * All rights reserved.
 */
package com.xiaohujr.xuexue.vm.exceptions;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

/**
 * jdk1.6和jdk1.7的方法区和常量池都在堆内存中,1.8已经独立出来,在本地内存上划取空间存储.叫元空间.
 * 在jdk1.6和1.7运行时需要指定permSize空间.
 * <p>
 * 方法区内存溢出
 * <p>
 * 方法区用于存放java类的相关信息，如类名、访问修饰符、常量池、字段描述、方法描述等。在类加载器加载class文件到内存中的时候，JVM会提取其中的类信息，并将这些类信息放到方法区中。
 * 当需要存储这些类信息，而方法区的内存占用又已经达到最大值（通过-XX:MaxPermSize）；将会抛出OutOfMemoryError异常对于这种情况的测试，基本的思路是运行时产生大量的类去填满方法区，直到溢出。这里需要借助CGLib直接操作字节码运行时，生成了大量的动态类。
 *
 * @author Xue Xue (xuexue1@huli.com)
 * @version $Id$
 * @since 2018/5/3
 */
public class JavaMethodAreaOOM {
    /**
     * -XX:MaxMetaspaceSize=10m       元空间大小配置.
     * Caused by: java.lang.OutOfMemoryError: Metaspace
     *
     * @param args 参数.
     */
    public static void main(String[] args) {
        while (true) {
            Enhancer enhancer = new Enhancer();
            enhancer.setSuperclass(OOMObject.class);
            enhancer.setUseCache(false);
            enhancer.setCallback(new MethodInterceptor() {
                @Override
                public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
                    return proxy.invokeSuper(obj, args);
                }
            });
            enhancer.create();
        }
    }

    static class OOMObject {
    }
}
